package Utilities;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;

import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import DataStorageClasses.EmailInfo;
import Database.DatabaseConnector;
import ExceptionClasses.CantAccessEmailException;

public class EmailClient 
{
	private DatabaseConnector db;
	private String username;
	private String password;
	private String business;
	
	public EmailClient(String business) throws CantAccessEmailException
	{
		db = new DatabaseConnector();
		EmailInfo info = db.getEmailInfo(business);
		
		if (info == null) {
			throw new CantAccessEmailException();
		}
		
		this.username = info.getEmail();
		this.password = info.getPassword();
		this.business = business;
		
		if (username == null || password == null) {
			throw new CantAccessEmailException();
		}
	}
	
	
	/*
	 * Throws: this throws a messaging exception that could be caused by two things: one is one of the addresses is an invalid type
	 * 		   or two something is wrong with the message, most likely the message is empty. So you will first have to check if the 
	 * 		   MessagingException is of time AddressException and then act accordingly. A solution to the second would be to make 
	 * 		   sure the msg is never empty (add a space or something) and then call this method.
	 */
	public void sendEmails(String[] address, String msg) throws MessagingException
	{
		Properties properties = new Properties();
		
		properties.put("mail.smtp.starttls.enable", "true");
		properties.put("mail.smtp.auth", "true");
		properties.put("mail.smtp.port", "587");
		
		InternetAddress[] adrs = new InternetAddress[address.length];
		Session session = Session.getInstance(properties);
		
		try {
			for (int i=0; i<address.length; i++)
			{
				adrs[i] = new InternetAddress(address[i]);
			}
			
			MimeMessage message = new MimeMessage(session);
			message.setText("asdfasdf");
			message.addRecipients(Message.RecipientType.TO, adrs);
			message.setText(msg);
			
			Transport tr = session.getTransport("smtp");
			tr.connect("smtp.gmail.com", username, password);
			message.saveChanges();      // don't forget this
			
			tr.sendMessage(message, message.getAllRecipients());
			tr.close();
		} 
		
		catch (NoSuchProviderException e) {
			e.printStackTrace();
		} 
	}
	
	/*
	 * Throws: this throws a messaging exception that could be caused by two things: one is one of the addresses is an invalid type
	 * 		   or two something is wrong with the message, most likely the message is empty. So you will first have to check if the 
	 * 		   MessagingException is of time AddressException and then act accordingly. A solution to the second would be to make 
	 * 		   sure the msg is never empty (add a space or something) and then call this method.
	 */
	public void sendEmail(String address, String msg) throws MessagingException
	{
		Properties properties = new Properties();
		
		properties.put("mail.smtp.starttls.enable", "true");
		properties.put("mail.smtp.auth", "true");
		properties.put("mail.smtp.port", "587");
		
		InternetAddress adrs = new InternetAddress(address);
		Session session = Session.getInstance(properties);
		
		try {
			
			MimeMessage message = new MimeMessage(session);
			message.setText("asdfasdf");
			message.addRecipient(Message.RecipientType.TO, adrs);
			message.setText(msg);
			
			Transport tr = session.getTransport("smtp");
			tr.connect("smtp.gmail.com", username, password);
			message.saveChanges();      // don't forget this
			
			tr.sendMessage(message, message.getAllRecipients());
			tr.close();
		} 
		
		catch (NoSuchProviderException e) {
			e.printStackTrace();
		} 
	}
	
	public EmailInbox getInbox(int num, int strt)
	{
		Properties properties = new Properties();
		
		properties.put("mail.imap.ssl.enable", "true");
		properties.put("mail.imap.port", "993");
		
		Session session = Session.getInstance(properties);
		
		try {
			Store store = session.getStore("imap");
			store.connect("imap.gmail.com", username, password);
			Folder folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);
			
			ArrayList<EmailHeader> headers = new ArrayList<EmailHeader>();
			
			int msgCount = folder.getMessageCount();
			int index;
			
			int numMsgs;
			
			if (num >= msgCount) {
				numMsgs = msgCount;
			}
			else {
				numMsgs = num;
			}
			
			int start = num*strt;
			
			for (index=0; index < numMsgs && msgCount-(start + index)>=1; index++) {
				System.out.println(start);
				Message message = folder.getMessage(msgCount-(start+index));
				
				headers.add(new EmailHeader(message.getFrom()[0].toString(),message.getSubject(), message.getMessageNumber(), message.getSentDate()));
			}
			
			
			folder.close(true);
			
			boolean more=true;
			
			if (start+index == msgCount) {
				more = false;
			}
			
			return new EmailInbox(headers, more);
			
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} 
		
		return null;
	}
	
	public EmailInbox getInbox(int num, int strt, String sender)
	{
		Properties properties = new Properties();
		
		properties.put("mail.imap.ssl.enable", "true");
		properties.put("mail.imap.port", "993");
		
		Session session = Session.getInstance(properties);
		
		try {
			Store store = session.getStore("imap");
			store.connect("imap.gmail.com", username, password);
			Folder folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);
			
			ArrayList<EmailHeader> headers = new ArrayList<EmailHeader>();
			
			int msgCount = folder.getMessageCount();
			int index;
			
			int numMsgs;
			
			if (num >= msgCount) {
				numMsgs = msgCount;
			}
			else {
				numMsgs = num;
			}
			
			int start = num*strt;
			
			for (index=0; index < numMsgs && msgCount-index>=0; index++) {
				Message message = folder.getMessage(msgCount-(start+index));
				Address address = message.getFrom()[0];
				
				if (address instanceof InternetAddress) {
					if(((InternetAddress) message.getFrom()[0]).getAddress().compareTo(sender) == 0)
						headers.add(new EmailHeader(address.toString(),message.getSubject(), message.getMessageNumber(), message.getSentDate()));
				}
			}
			
			folder.close(true);
			
			boolean more=true;
			
			if (start+index == msgCount) {
				more = false;
			}
			
			return new EmailInbox(headers, more);
			
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} 
		
		return null;
	}
	
	public void getContactList()
	{
		Properties properties = new Properties();
		
		properties.put("mail.imap.ssl.enable", "true");
		properties.put("mail.imap.port", "993");
		
		Session session = Session.getInstance(properties);
		
		try {
			Store store = session.getStore("imap");
			store.connect("imap.gmail.com", username, password);
			
			Folder[] f = store.getDefaultFolder().list();
		    for(Folder fd:f)
		        System.out.println(">> "+fd.getName());
			
			//folder.close(true);
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} 
		
	}
	
	public String openMessage(int msgIndex) throws IOException 
	{
		Properties properties = new Properties();
		
		properties.put("mail.imap.ssl.enable", "true");
		properties.put("mail.imap.port", "993");
		
		Session session = Session.getInstance(properties);
		
		try {
			StringBuffer buf = new StringBuffer();
			Store store = session.getStore("imap");
			store.connect("imap.gmail.com", username, password);
			Folder folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);
			
			Message message = folder.getMessage(msgIndex);
			Object object = message.getContent();
			
			if(object instanceof Multipart) {
			
				Multipart part = (Multipart)object;
				int numParts = part.getCount();
				
				for (int i=0; i<numParts; i++) {
					BodyPart bp = part.getBodyPart(i);
					String disposition = bp.getDisposition();
					
					if (disposition == null)
						buf.append(bp.getContent().toString());
				}
			}
			String msg = buf.toString();
			folder.close(true);
			return msg;
			
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public ArrayList<EmailHeader> deleteMessage(int msgIndex, int numMsg, int strtIndex)
	{
		Properties properties = new Properties();
		
		properties.put("mail.imap.ssl.enable", "true");
		properties.put("mail.imap.port", "993");
		
		Session session = Session.getInstance(properties);
		
		try {
			Store store = session.getStore("imap");
			store.connect("imap.gmail.com", username, password);
			Folder folder = store.getFolder("INBOX");
			folder.open(Folder.READ_WRITE);
			
			Message message = folder.getMessage(msgIndex);
			message.setFlag(Flags.Flag.DELETED, true);
			
			folder.close(true);
			
			return getInbox(numMsg, strtIndex).getHeaders();
		}
		
		catch (NoSuchProviderException e){
			e.printStackTrace();
		} catch (MessagingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	public boolean updateSubscribers(String message) throws MessagingException
	{
		String[] emails = db.getSubscriberEmails(business);
		if (emails != null) {
			sendEmails(emails, message);
			return true;
		}
		
		return false;
	}
	
	public class EmailHeader
	{
		String sender;
		String subject;
		int msgIndex;
		Date date;
		
		public EmailHeader(String sender, String subject, int msgIndex, Date date)
		{
			this.sender = sender;
			this.subject = subject;
			this.msgIndex = msgIndex;
			this.date = date;
		}
		
		public String getSender()
		{
			return sender;
		}
		
		public String getSubject()
		{
			return subject;
		}
		
		public int getIndex()
		{
			return msgIndex;
		}
		
		public Date getDate()
		{
			return date;
		}
	}
	
	public class EmailInbox
	{
		private ArrayList<EmailHeader> headers;
		private boolean more;
		
		public EmailInbox(ArrayList<EmailHeader> headers2, boolean more)
		{
			this.headers = headers2;
			this.more = more;
		}
		
		public ArrayList<EmailHeader> getHeaders()
		{
			return headers;
		}
		
		public boolean areMore()
		{
			return more;
		}
	}
	
	public static void main(String args[])
	{
		EmailClient email;
		try {
			email = new EmailClient("business");
			//String[] emails = {"brianmcmahon135@gmail.com", "mamhillier@gmail.com"};
			
			String message = "Stuff";
			try {
				email.updateSubscribers("stuff and such");
			} catch (MessagingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		} catch (CantAccessEmailException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
